/**
 * 
 */
package pl.com.qapps.datastore.objectify;

import pl.com.qapps.datastore.Datastore;
import pl.com.qapps.datastore.GaeHelper;

import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreService.KeyRangeState;
import com.google.appengine.api.datastore.DatastoreServiceConfig;
import com.googlecode.objectify.AccessibleKeyRange;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.KeyRange;
import com.googlecode.objectify.ObjectifyFactory;

/**
 * {@link ObjectofyFactory} that don't uses Google Datastore as data source but
 * provides a way to choose where the data is stored by providing an
 * implementation of {@link Datastore}
 * 
 * @author qba
 */
public class OfyFactory extends ObjectifyFactory {

	private final Datastore ds;

	/**
	 * Creates {@link ObjectifyFactory} which uses the provided
	 * {@link Datastore} implementation data source, in contrary to standard
	 * {@link ObjectofyfFactory} which uses Google Datastore.
	 * 
	 * @param ds
	 *            chosen {@link Datastore} implementation
	 * @throws IllegalArgumentException
	 *             if ds is {@code null}
	 */
	public OfyFactory(Datastore ds) throws IllegalArgumentException {
		if (ds == null)
			throw new IllegalArgumentException("ds cannot be null");
		this.ds = ds;
	}

	@Override
	protected AsyncDatastoreService getRawAsyncDatastoreService(
			DatastoreServiceConfig cfg) {
		return ds.getAsyncDatastoreService(cfg);
	}

	@Override
	protected DatastoreService getRawDatastoreService(DatastoreServiceConfig cfg) {
		return ds.getDatastoreService(cfg);
	}

	@Override
	public <T> KeyRange<T> allocateIds(Class<T> clazz, long num) {
		String kind = Key.getKind(clazz);
		return new AccessibleKeyRange<T>(ds.getDatastoreService(null)
				.allocateIds(kind, num));
	}

	@Override
	public <T> KeyRange<T> allocateIds(Object parentKeyOrEntity,
			Class<T> clazz, long num) {
		Key<?> parent = this.getKey(parentKeyOrEntity);
		String kind = Key.getKind(clazz);

		return new AccessibleKeyRange<T>(ds.getDatastoreService(null)
				.allocateIds(parent.getRaw(), kind, num));
	}

	@Override
	public <T> KeyRangeState allocateIdRange(KeyRange<T> range) {
		return ds.getDatastoreService(null).allocateIdRange(range.getRaw());
	}

	@Override
	public <T> Key<T> stringToKey(String stringifiedKey) {
		GaeHelper.registerEnvironment();
		return super.stringToKey(stringifiedKey);
	}

	@Override
	public String keyToString(Key<?> key) {
		GaeHelper.registerEnvironment();
		return super.keyToString(key);
	}

}
